#include "stdafx.h"
#include "..\headers\LuaEngine.h"
#include "..\headers\Components.h"
#include "..\headers\CameraComponents.h"
#include "..\headers\LuaGameObject.h"
#include "..\headers\LuaSystem.h"
#include "luabind\operator.hpp"

#ifdef WIN32
#include <sys/stat.h>
#include <sys/types.h>
#endif

#include "..\headers\GameTime.h"

namespace ne{

LuaEngine::LuaEngine(void) : m_L(nullptr){
#ifdef DEV_MODE
	m_timer = 0.0f;
	m_timeLimit = 1.0f;
#endif
}

bool LuaEngine::Init(PhysicsWorld* physicsWorld,StateListener* stateListener,InputSystem* inputSystem,GameTime* gameTime){
	m_L = luaL_newstate();
	luaL_openlibs(m_L);
	lua_atpanic(m_L, LuaEngine::AtPanic);
	luabind::open(m_L);
	LuaSystem::Init(this,physicsWorld,stateListener);
	Input::Init(this,inputSystem);
	Time::Init(this,gameTime);
	//btPairCachingGhostObject*
	// Export enums for components
	luabind::module(m_L) [
		luabind::class_<ComponentFlagTypes>("Component")
		.enum_("component_flags")[
			luabind::value("Animation",COMPONENT_ANIMATION),
			luabind::value("Mesh",COMPONENT_MESH),
			luabind::value("Rigidbody",COMPONENT_RIGIDBODY),
			luabind::value("BoxCollider",COMPONENT_COLLIDER_BOX),
			luabind::value("SphereCollider",COMPONENT_COLLIDER_SPHERE),
			luabind::value("CapsuleCollider",COMPONENT_COLLIDER_CAPSULE),
			luabind::value("StaticMeshCollider",COMPONENT_COLLIDER_STATIC_MESH),
			luabind::value("Light",COMPONENT_LIGHT),
			luabind::value("Camera",COMPONENT_CAMERA),
			luabind::value("FirstPersonCamera",COMPONENT_FIRST_PERSON_CAMERA),
			luabind::value("CharacterController",COMPONENT_CHARACTER_CONTROLLER),
			luabind::value("ThirdPersonCamera",COMPONENT_THIRD_PERSON_CAMERA)
		]
	];
	
	// Exporting OIS keyboard
	luabind::module(m_L)[
		luabind::class_<OIS::Keyboard,OIS::Mouse>("OIS")
			.enum_("input_flags")[
				luabind::value("Centered",OIS::Pov::Centered),
				luabind::value("East",OIS::Pov::East),
				luabind::value("North",OIS::Pov::North),
				luabind::value("NorthEast",OIS::Pov::NorthEast),
				luabind::value("NorthWest",OIS::Pov::NorthWest),
				luabind::value("South",OIS::Pov::South),
				luabind::value("SouthEast",OIS::Pov::SouthEast),
				luabind::value("SouthWest",OIS::Pov::SouthWest),
				luabind::value("West",OIS::Pov::West),
				luabind::value("MB_Left",OIS::MB_Left),
				luabind::value("MB_Right",OIS::MB_Right),
				luabind::value("MB_Middle",OIS::MB_Middle),
				luabind::value("MB_Button3",OIS::MB_Button3),
				luabind::value("MB_Button4",OIS::MB_Button4),
				luabind::value("MB_Button5",OIS::MB_Button5),
				luabind::value("MB_Button6",OIS::MB_Button6),
				luabind::value("MB_Button7",OIS::MB_Button7),
				luabind::value("KC_0",OIS::KC_0),
				luabind::value("KC_1",OIS::KC_1),
				luabind::value("KC_2",OIS::KC_2),
				luabind::value("KC_3",OIS::KC_3),
				luabind::value("KC_4",OIS::KC_4),
				luabind::value("KC_5",OIS::KC_5),
				luabind::value("KC_6",OIS::KC_6),
				luabind::value("KC_7",OIS::KC_7),
				luabind::value("KC_8",OIS::KC_8),
				luabind::value("KC_9",OIS::KC_9),
				luabind::value("KC_A",OIS::KC_A),
				luabind::value("KC_ABNT_C1",OIS::KC_ABNT_C1),
				luabind::value("KC_ABNT_C2",OIS::KC_ABNT_C2),
				luabind::value("KC_ADD",OIS::KC_ADD),
				luabind::value("KC_APOSTROPHE",OIS::KC_APOSTROPHE),
				luabind::value("KC_APPS",OIS::KC_APPS),
				luabind::value("KC_AT",OIS::KC_AT),
				luabind::value("KC_AX",OIS::KC_AX),
				luabind::value("KC_B",OIS::KC_B),
				luabind::value("KC_BACK",OIS::KC_BACK),
				luabind::value("KC_BACKSLASH",OIS::KC_BACKSLASH),
				luabind::value("KC_C",OIS::KC_C),
				luabind::value("KC_CALCULATOR",OIS::KC_CALCULATOR),
				luabind::value("KC_CAPITAL",OIS::KC_CAPITAL),
				luabind::value("KC_COLON",OIS::KC_COLON),
				luabind::value("KC_COMMA",OIS::KC_COMMA),
				luabind::value("KC_CONVERT",OIS::KC_CONVERT),
				luabind::value("KC_D",OIS::KC_D),
				luabind::value("KC_DECIMAL",OIS::KC_DECIMAL),
				luabind::value("KC_DELETE",OIS::KC_DELETE),
				luabind::value("KC_DIVIDE",OIS::KC_DIVIDE),
				luabind::value("KC_DOWN",OIS::KC_DOWN),
				luabind::value("KC_E",OIS::KC_E),
				luabind::value("KC_END",OIS::KC_END),
				luabind::value("KC_EQUALS",OIS::KC_EQUALS),
				luabind::value("KC_ESCAPE",OIS::KC_ESCAPE),
				luabind::value("KC_F",OIS::KC_F),
				luabind::value("KC_F1",OIS::KC_F1),
				luabind::value("KC_F10",OIS::KC_F10),
				luabind::value("KC_F11",OIS::KC_F11),
				luabind::value("KC_F12",OIS::KC_F12),
				luabind::value("KC_F13",OIS::KC_F13),
				luabind::value("KC_F14",OIS::KC_F14),
				luabind::value("KC_F15",OIS::KC_F15),
				luabind::value("KC_F2",OIS::KC_F2),
				luabind::value("KC_F3",OIS::KC_F3),
				luabind::value("KC_F4",OIS::KC_F4),
				luabind::value("KC_F5",OIS::KC_F5),
				luabind::value("KC_F6",OIS::KC_F6),
				luabind::value("KC_F7",OIS::KC_F7),
				luabind::value("KC_F8",OIS::KC_F8),
				luabind::value("KC_F9",OIS::KC_F9),
				luabind::value("KC_G",OIS::KC_G),
				luabind::value("KC_GRAVE",OIS::KC_GRAVE),
				luabind::value("KC_H",OIS::KC_H),
				luabind::value("KC_HOME",OIS::KC_HOME),
				luabind::value("KC_I",OIS::KC_I),
				luabind::value("KC_INSERT",OIS::KC_INSERT),
				luabind::value("KC_J",OIS::KC_J),
				luabind::value("KC_K",OIS::KC_K),
				luabind::value("KC_KANA",OIS::KC_KANA),
				luabind::value("KC_KANJI",OIS::KC_KANJI),
				luabind::value("KC_L",OIS::KC_L),
				luabind::value("KC_LBRACKET",OIS::KC_LBRACKET),
				luabind::value("KC_LCONTROL",OIS::KC_LCONTROL),
				luabind::value("KC_LEFT",OIS::KC_LEFT),
				luabind::value("KC_LMENU",OIS::KC_LMENU),
				luabind::value("KC_LSHIFT",OIS::KC_LSHIFT),
				luabind::value("KC_LWIN",OIS::KC_LWIN),
				luabind::value("KC_M",OIS::KC_M),
				luabind::value("KC_MAIL",OIS::KC_MAIL),
				luabind::value("KC_MEDIASELECT",OIS::KC_MEDIASELECT),
				luabind::value("KC_MEDIASTOP",OIS::KC_MEDIASTOP),
				luabind::value("KC_MINUS",OIS::KC_MINUS),
				luabind::value("KC_MULTIPLY",OIS::KC_MULTIPLY),
				luabind::value("KC_MUTE",OIS::KC_MUTE),
				luabind::value("KC_MYCOMPUTER",OIS::KC_MYCOMPUTER),
				luabind::value("KC_N",OIS::KC_N),
				luabind::value("KC_NEXTTRACK",OIS::KC_NEXTTRACK),
				luabind::value("KC_NOCONVERT",OIS::KC_NOCONVERT),
				luabind::value("KC_NUMLOCK",OIS::KC_NUMLOCK),
				luabind::value("KC_NUMPAD0",OIS::KC_NUMPAD0),
				luabind::value("KC_NUMPAD1",OIS::KC_NUMPAD1),
				luabind::value("KC_NUMPAD2",OIS::KC_NUMPAD2),
				luabind::value("KC_NUMPAD3",OIS::KC_NUMPAD3),
				luabind::value("KC_NUMPAD4",OIS::KC_NUMPAD4),
				luabind::value("KC_NUMPAD5",OIS::KC_NUMPAD5),
				luabind::value("KC_NUMPAD6",OIS::KC_NUMPAD6),
				luabind::value("KC_NUMPAD7",OIS::KC_NUMPAD7),
				luabind::value("KC_NUMPAD8",OIS::KC_NUMPAD8),
				luabind::value("KC_NUMPAD9",OIS::KC_NUMPAD9),
				luabind::value("KC_NUMPADCOMMA",OIS::KC_NUMPADCOMMA),
				luabind::value("KC_NUMPADENTER",OIS::KC_NUMPADENTER),
				luabind::value("KC_NUMPADEQUALS",OIS::KC_NUMPADEQUALS),
				luabind::value("KC_O",OIS::KC_O),
				luabind::value("KC_OEM_102",OIS::KC_OEM_102),
				luabind::value("KC_P",OIS::KC_P),
				luabind::value("KC_PAUSE",OIS::KC_PAUSE),
				luabind::value("KC_PERIOD",OIS::KC_PERIOD),
				luabind::value("KC_PGDOWN",OIS::KC_PGDOWN),
				luabind::value("KC_PGUP",OIS::KC_PGUP),
				luabind::value("KC_PLAYPAUSE",OIS::KC_PLAYPAUSE),
				luabind::value("KC_POWER",OIS::KC_POWER),
				luabind::value("KC_PREVTRACK",OIS::KC_PREVTRACK),
				luabind::value("KC_Q",OIS::KC_Q),
				luabind::value("KC_R",OIS::KC_R),
				luabind::value("KC_RBRACKET",OIS::KC_RBRACKET),
				luabind::value("KC_RCONTROL",OIS::KC_RCONTROL),
				luabind::value("KC_RETURN",OIS::KC_RETURN),
				luabind::value("KC_RIGHT",OIS::KC_RIGHT),
				luabind::value("KC_RMENU",OIS::KC_RMENU),
				luabind::value("KC_RSHIFT",OIS::KC_RSHIFT),
				luabind::value("KC_RWIN",OIS::KC_RWIN),
				luabind::value("KC_S",OIS::KC_S),
				luabind::value("KC_SCROLL",OIS::KC_SCROLL),
				luabind::value("KC_SEMICOLON",OIS::KC_SEMICOLON),
				luabind::value("KC_SLASH",OIS::KC_SLASH),
				luabind::value("KC_SLEEP",OIS::KC_SLEEP),
				luabind::value("KC_SPACE",OIS::KC_SPACE),
				luabind::value("KC_STOP",OIS::KC_STOP),
				luabind::value("KC_SUBTRACT",OIS::KC_SUBTRACT),
				luabind::value("KC_SYSRQ",OIS::KC_SYSRQ),
				luabind::value("KC_T",OIS::KC_T),
				luabind::value("KC_TAB",OIS::KC_TAB),
				luabind::value("KC_U",OIS::KC_U),
				luabind::value("KC_UNASSIGNED",OIS::KC_UNASSIGNED),
				luabind::value("KC_UNDERLINE",OIS::KC_UNDERLINE),
				luabind::value("KC_UNLABELED",OIS::KC_UNLABELED),
				luabind::value("KC_UP",OIS::KC_UP),
				luabind::value("KC_V",OIS::KC_V),
				luabind::value("KC_VOLUMEDOWN",OIS::KC_VOLUMEDOWN),
				luabind::value("KC_VOLUMEUP",OIS::KC_VOLUMEUP),
				luabind::value("KC_W",OIS::KC_W),
				luabind::value("KC_WAKE",OIS::KC_WAKE),
				luabind::value("KC_WEBBACK",OIS::KC_WEBBACK),
				luabind::value("KC_WEBFAVORITES",OIS::KC_WEBFAVORITES),
				luabind::value("KC_WEBFORWARD",OIS::KC_WEBFORWARD),
				luabind::value("KC_WEBHOME",OIS::KC_WEBHOME),
				luabind::value("KC_WEBREFRESH",OIS::KC_WEBREFRESH),
				luabind::value("KC_WEBSEARCH",OIS::KC_WEBSEARCH),
				luabind::value("KC_WEBSTOP",OIS::KC_WEBSTOP),
				luabind::value("KC_X",OIS::KC_X),
				luabind::value("KC_Y",OIS::KC_Y),
				luabind::value("KC_YEN",OIS::KC_YEN),
				luabind::value("KC_Z",OIS::KC_Z)
			]
	];

	luabind::module(m_L) [
		luabind::class_<Ogre::Light::LightTypes>("LightType")
		.enum_("light_flags")[
			luabind::value("Directional",Ogre::Light::LT_DIRECTIONAL),
			luabind::value("Point",Ogre::Light::LT_POINT),
			luabind::value("Spotlight",Ogre::Light::LT_SPOTLIGHT)
		]
	];

	luabind::module(m_L) [
		luabind::class_<btCollisionObject>("btCollisionObject")
	];

	luabind::module(m_L) [
		luabind::class_<btPairCachingGhostObject>("btPairCachingGhostObject")
	];

	
	luabind::module(m_L) [
		luabind::class_<CObjContainer>("CObjContainer")
	];

	luabind::module(m_L) [
		luabind::class_<Ogre::SceneNode>("SceneNode")
	];

	luabind::module(m_L) [
		luabind::class_<Ogre::Entity>("Entity")
	];

	// Export game object class base
	// All Lua game objects will inherit from our base GameObject class
	luabind::module(m_L) [
		luabind::class_<GameObject,LuaGameObject>("GameObject")
			.def(luabind::constructor<>())
			.def("onStartup",&GameObject::onStartup,LuaGameObject::default_onStartup)
			.def("onInit",&GameObject::onInit,&LuaGameObject::default_onInit)
			.def("onUpdate",&GameObject::onUpdate,&LuaGameObject::default_onUpdate)
			.def("onSimulation",&GameObject::onSimulation,&LuaGameObject::default_onSimulation)
			.def("onRemove",&GameObject::onRemove,&LuaGameObject::default_onRemove)
			.def("beginContact",&GameObject::beginContact,&LuaGameObject::default_beginContact)
			.def("endContact",&GameObject::endContact,&LuaGameObject::default_endContact)
			.def("AddComponent",(luabind::object(GameObject::*)(int,lua_State*))&GameObject::AddComponent)
			.def("GetComponent",(luabind::object(GameObject::*)(int,lua_State*))&GameObject::GetComponent)
			.def("SetPosition",(void(GameObject::*)(float,float,float))&GameObject::SetPosition)
			.def("SetPosition",(void(GameObject::*)(const Ogre::Vector3&))&GameObject::SetPosition)
			.def("Translate",(void(GameObject::*)(float,float,float))&GameObject::Translate)
			.def("Translate",(void(GameObject::*)(const Ogre::Vector3&))&GameObject::Translate)
			.def("GetPosition",&GameObject::GetPosition)
			.def("GetOrientation",&GameObject::GetOrientation)
			.def("SetOrientation",&GameObject::SetOrientation)
			.def("SetDirection",&GameObject::SetDirection)
			.def("GetScale",&GameObject::GetScale)
			.def("SetScale",(void(GameObject::*)(float,float,float))&GameObject::SetScale)
			.def("SetScale",(void(GameObject::*)(const Ogre::Vector3&))&GameObject::SetScale)
			.def("SetId",&GameObject::SetId)
			.def("GetId",&GameObject::GetId)
			.def("GetSceneNode",&GameObject::GetSceneNode)
			.def("Roll",&GameObject::Roll)
			.def("Pitch",&GameObject::Pitch)
			.def("Yaw",&GameObject::Yaw)
	];
	
	luabind::module(m_L)[
		luabind::class_<IgnoreObjectCast>("IgnoreObjectCast")
			.def(luabind::constructor<const CObjContainer&>())
			.def("HasHit",&IgnoreObjectCast::HasHit)
			.def("GetGameObject",&IgnoreObjectCast::GetGameObject)
			.def("GetHitPointWorld",&IgnoreObjectCast::GetHitPointWorld)
			.def("GetHitNormalWorld",&IgnoreObjectCast::GetHitNormalWorld)
	];

	luabind::module(m_L) [
		luabind::class_<AnimationComponent>("Animation")
			.def("PlayAnimation",&AnimationComponent::PlayAnimation)
			.def("PauseAnimation",&AnimationComponent::PauseAnimation)
			.def("StopAnimation",&AnimationComponent::StopAnimation)
			.def("IsPaused",&AnimationComponent::IsPaused)
			.enum_("Blend")[
				luabind::value("Avarage",(int)Ogre::SkeletonAnimationBlendMode::ANIMBLEND_AVERAGE),
				luabind::value("Cumulative",(int)Ogre::SkeletonAnimationBlendMode::ANIMBLEND_CUMULATIVE)
			]
	];

	luabind::module(m_L) [
		luabind::class_<CameraComponent>("Camera")
			.def("GetDirection",&CameraComponent::GetDirection)
			.def("SetPosition",(void(CameraComponent::*)(float,float,float))&CameraComponent::SetPosition)
			.def("SetPosition",(void(CameraComponent::*)(const Ogre::Vector3&))&CameraComponent::SetPosition)
			.def("GetPosition",&CameraComponent::GetPosition)
			.def("GetDerivedPosition",&CameraComponent::GetDerivedPosition)
			.def("SetFarClipDistance",&CameraComponent::SetFarClipDistance)
			.def("SetNearClipDistance",&CameraComponent::SetNearClipDistance)
			.def("GetOrientation",&CameraComponent::GetOrientation)
	];
	luabind::module(m_L) [
		luabind::class_<FirstPersonCameraComponent,CameraComponent>("FirstPersonCamera")
			.def("SetRotationSpeed",&FirstPersonCameraComponent::SetRotationSpeed)
			.def("SetMovementSpeed",&FirstPersonCameraComponent::SetMovementSpeed)
			.def("LimitAngle",&FirstPersonCameraComponent::LimitAngle)
			.def("EnableControl",&FirstPersonCameraComponent::EnableControl)
			.def("GetDirection",&CameraComponent::GetDirection)
			.def("SetPosition",(void(CameraComponent::*)(float,float,float))&CameraComponent::SetPosition)
			.def("SetPosition",(void(CameraComponent::*)(const Ogre::Vector3&))&CameraComponent::SetPosition)
			.def("GetPosition",&CameraComponent::GetPosition)
			.def("GetDerivedPosition",&CameraComponent::GetDerivedPosition)
			.def("SetFarClipDistance",&CameraComponent::SetFarClipDistance)
			.def("SetNearClipDistance",&CameraComponent::SetNearClipDistance)
			.def("GetOrientation",&CameraComponent::GetOrientation)
	];
	luabind::module(m_L) [
		luabind::class_<ThirdPersonCameraComponent,CameraComponent>("ThirdPersonCamera")
			.def("GetDirection",&CameraComponent::GetDirection)
			.def("SetPosition",(void(CameraComponent::*)(float,float,float))&CameraComponent::SetPosition)
			.def("SetPosition",(void(CameraComponent::*)(const Ogre::Vector3&))&CameraComponent::SetPosition)
			.def("GetPosition",&CameraComponent::GetPosition)
			.def("GetDerivedPosition",&CameraComponent::GetDerivedPosition)
			.def("SetFarClipDistance",&CameraComponent::SetFarClipDistance)
			.def("SetNearClipDistance",&CameraComponent::SetNearClipDistance)
			.def("GetOrientation",&CameraComponent::GetOrientation)
			.def("SetTarget",&ThirdPersonCameraComponent::SetTarget)
			.def("GetDirectionFromCamera",&ThirdPersonCameraComponent::GetDirectionFromCamera)
			.def("GetCameraOrientation",&ThirdPersonCameraComponent::GetCameraOrientation)
			.def("SetPitchLimit",&ThirdPersonCameraComponent::SetPitchLimit)
			.def("SetVerticalSpeed",&ThirdPersonCameraComponent::SetVerticalSpeed)
			.def("SetHorizontalSpeed",&ThirdPersonCameraComponent::SetHorizontalSpeed)
			.def("SetCameraSpeed",&ThirdPersonCameraComponent::SetCameraSpeed)
			.def("GetVerticalSpeed",&ThirdPersonCameraComponent::GetVerticalSpeed)
			.def("GetHorizontalSpeed",&ThirdPersonCameraComponent::GetHorizontalSpeed)
			.def("SetVerticalInvert",&ThirdPersonCameraComponent::SetVerticalInvert)
			.def("SetHorizontalInvert",&ThirdPersonCameraComponent::SetHorizontalInvert)
			.def("SetCameraInvert",&ThirdPersonCameraComponent::SetCameraInvert)
			.def("IsVerticalInvert",&ThirdPersonCameraComponent::IsVerticalInvert)
			.def("IsHorizontalInvert",&ThirdPersonCameraComponent::IsHorizontalInvert)
			.def("SetZoomSpeed",&ThirdPersonCameraComponent::SetZoomSpeed)
			.def("SetMaxZoomDistance",&ThirdPersonCameraComponent::SetMaxZoomDistance)
			.def("SetMinZoomDistance",&ThirdPersonCameraComponent::SetMinZoomDistance)
	];

	luabind::module(m_L) [
		luabind::class_<MeshComponent>("Mesh")
			.def("LoadMesh",&MeshComponent::LoadMesh)
			.def("SetMaterial",&MeshComponent::SetMaterial)
			.def("CreatePlane",&MeshComponent::CreatePlane)
			.def("DestroyPlane",&MeshComponent::DestroyPlane)
			.def("SetScale",(void(MeshComponent::*)(float,float,float))&MeshComponent::SetScale)
			.def("SetScale",(void(MeshComponent::*)(const Ogre::Vector3&))&MeshComponent::SetScale)
			.def("GetScale",(const Ogre::Vector3&(MeshComponent::*)(void))&MeshComponent::GetScale)
			.def("SetOrientation",(void(MeshComponent::*)(float,float,float,float))&MeshComponent::SetOrientation)
			.def("SetOrientation",(void(MeshComponent::*)(const Ogre::Quaternion&))&MeshComponent::SetOrientation)
			.def("GetOrientation",&MeshComponent::GetOrientation)
			.def("Translate",(void(MeshComponent::*)(float,float,float))&MeshComponent::Translate)
			.def("Translate",(void(MeshComponent::*)(const Ogre::Vector3&))&MeshComponent::Translate)
			.def("SetPosition",(void(MeshComponent::*)(float,float,float))&MeshComponent::SetPosition)
			.def("SetPosition",(void(MeshComponent::*)(const Ogre::Vector3&))&MeshComponent::SetPosition)
			.def("Yaw",&MeshComponent::Yaw)
			.def("Pitch",&MeshComponent::Pitch)
			.def("Roll",&MeshComponent::Roll)
			.def("GetPosition",&MeshComponent::GetPosition)
			.def("IsVisible",&MeshComponent::IsVisible)
			.def("SetVisible",&MeshComponent::SetVisible)
			.def("SetSkeletonBlendMode",&MeshComponent::SetSkeletonBlendMode)
	];

	luabind::module(m_L) [
		luabind::class_<RigidBodyComponent>("RigidBody")
			.def("ApplyImpulse",(void(RigidBodyComponent::*)(const Ogre::Vector3&))&RigidBodyComponent::ApplyImpulse)
			.def("ApplyImpulse",(void(RigidBodyComponent::*)(const Ogre::Vector3&,const Ogre::Vector3&))&RigidBodyComponent::ApplyImpulse)
			.def("SetRestitution",&RigidBodyComponent::SetRestitution)
			.def("GetRestitution",&RigidBodyComponent::GetRestitution)
			.def("GetMass",&RigidBodyComponent::GetMass)
			.def("SetMass",&RigidBodyComponent::SetMass)
			.def("GetGravity",&RigidBodyComponent::GetGravity)
			.def("SetGravity",(void(RigidBodyComponent::*)(float,float,float))&RigidBodyComponent::SetGravity)
			.def("SetGravity",(void(RigidBodyComponent::*)(const Ogre::Vector3&))&RigidBodyComponent::SetGravity)
			.def("GetCollisionObject",&RigidBodyComponent::GetCollisionObject)
			.def("SetFriction",&RigidBodyComponent::SetFriction)
			.def("GetFriction",&RigidBodyComponent::GetFriction)
			.enum_("Activation")[
				luabind::value("DisableDeactivation",DISABLE_DEACTIVATION),
				luabind::value("ActiveTag",ACTIVE_TAG),
				luabind::value("IslandSleeping",ISLAND_SLEEPING),
				luabind::value("WantsDeactivation",WANTS_DEACTIVATION),
				luabind::value("DisableSimulation",DISABLE_SIMULATION)
			]
	];

	luabind::module(m_L)[
		luabind::class_<CharacterControllerComponent>("CharacterController")
			.def("Create",(void(CharacterControllerComponent::*)(void))&CharacterControllerComponent::Create)
			.def("Create",(void(CharacterControllerComponent::*)(float,float))&CharacterControllerComponent::Create)
			.def("SetWalkDirection",(void(CharacterControllerComponent::*)(const Ogre::Vector3&))&CharacterControllerComponent::SetWalkDirection)
			.def("SetWalkDirection",(void(CharacterControllerComponent::*)(float,float,float))&CharacterControllerComponent::SetWalkDirection)
			.def("Jump",&CharacterControllerComponent::Jump)
			.def("SetMaxJumpHeight",&CharacterControllerComponent::SetMaxJumpHeight)
			.def("SetMaxSlope",&CharacterControllerComponent::SetMaxSlope)
			.def("SetGravity",&CharacterControllerComponent::SetGravity)
			.def("SetFallSpeed",&CharacterControllerComponent::SetFallSpeed)
			.def("SetJumpSpeed",&CharacterControllerComponent::SetJumpSpeed)
			.def("GetCollisionObject",&CharacterControllerComponent::GetCollisionObject)
			.def("SetShapeOffset",&CharacterControllerComponent::SetShapeOffset)
			.def("OnGround",&CharacterControllerComponent::OnGround)
	];

	luabind::module(m_L) [
		luabind::class_<LightComponent>("Light")
			.def("SetType",&LightComponent::SetType)
			.def("SetPosition",(void(LightComponent::*)(float,float,float))&LightComponent::SetPosition)
			.def("SetPosition",(void(LightComponent::*)(const Ogre::Vector3&))&LightComponent::SetPosition)
			.def("SetDirection",(void(LightComponent::*)(float,float,float))&LightComponent::SetDirection)
			.def("SetDirection",(void(LightComponent::*)(const Ogre::Vector3&))&LightComponent::SetDirection)
			.def("SetDiffuseColor",&LightComponent::SetDiffuseColor)
			.def("SetSpecularColor",&LightComponent::SetSpecularColor)
	];

	luabind::module(m_L) [
		luabind::class_<ColliderComponent>("Collider")
	];

	luabind::module(m_L) [
		luabind::class_<BoxColliderComponent,ColliderComponent>("BoxCollider")
			.def("Create",(void(BoxColliderComponent::*)(const Ogre::Vector3&))&BoxColliderComponent::Create)
			.def("Create",(void(BoxColliderComponent::*)(float,float,float))&BoxColliderComponent::Create)
			.def("Create",(void(BoxColliderComponent::*)(void))&BoxColliderComponent::Create)
			.def("SetOrigin",&ColliderComponent::SetOrigin)
	];

	luabind::module(m_L) [
		luabind::class_<SphereColliderComponent,ColliderComponent>("SphereCollider")
			.def("Create",(void(SphereColliderComponent::*)(void))&SphereColliderComponent::Create)
			.def("Create",(void(SphereColliderComponent::*)(float))&SphereColliderComponent::Create)
			.def("SetOrigin",&ColliderComponent::SetOrigin)
	];

	luabind::module(m_L) [
		luabind::class_<CapsuleColliderComponent,ColliderComponent>("CapsuleCollider")
			.def("Create",(void(CapsuleColliderComponent::*)(void))&CapsuleColliderComponent::Create)
			.def("Create",(void(CapsuleColliderComponent::*)(float,float))&CapsuleColliderComponent::Create)
			.def("SetOrigin",&ColliderComponent::SetOrigin)
	];

	luabind::module(m_L) [
		luabind::class_<StaticMeshColliderComponent>("StaticMeshCollider")
			.def("Create",&StaticMeshColliderComponent::Create)
	];

	//Exporting axis from OIS so we can access relative and absolute values for the mouse
	luabind::module(m_L)[
		luabind::class_<OIS::Axis>("Axis")
			.def_readonly("abs",&OIS::Axis::abs)
			.def_readonly("rel",&OIS::Axis::rel)
	];
	// Exporting a part of OIS::MouseState, combined with the above we can now get relative and absolute values in LUA for the mouse
	luabind::module(m_L)[
		luabind::class_<OIS::MouseState>("Mouse")
			.def_readonly("X",&OIS::MouseState::X)
			.def_readonly("Y",&OIS::MouseState::Y)
			.def_readonly("Z",&OIS::MouseState::Z)
	];

	luabind::module(m_L)[
		luabind::class_<Ogre::Radian>("Radian")
			.def(luabind::constructor<Ogre::Real>())
			.def(luabind::constructor<>())
			.def(luabind::constructor<Ogre::Radian&>())
			.def("ValueAngleUnits",&Ogre::Radian::valueAngleUnits)
			.def("ValueDegrees",&Ogre::Radian::valueDegrees)
			.def("ValueRadians",&Ogre::Radian::valueRadians)
			.def(luabind::tostring(luabind::self))
	];

	// Exporting Ogre::Vector3 class to LUA
	luabind::module(m_L)[
		luabind::class_<Ogre::Vector3>("Vector3")
			.def(luabind::constructor<Ogre::Real,Ogre::Real,Ogre::Real>())
			.def(luabind::constructor<>())
			.def(luabind::constructor<Ogre::Vector3&>())
			.def_readwrite("x",&Ogre::Vector3::x)
			.def_readwrite("y",&Ogre::Vector3::y)
			.def_readwrite("z",&Ogre::Vector3::z)
			.def("Distance",&Ogre::Vector3::distance)
			.def("SquaredDistance",&Ogre::Vector3::squaredDistance)
			.def("CrossProduct",&Ogre::Vector3::crossProduct)
			.def("Length",&Ogre::Vector3::length)
			.def("SquaredLength",&Ogre::Vector3::squaredLength)
			.def("DotProduct",&Ogre::Vector3::dotProduct)
			.def("Normalize",&Ogre::Vector3::normalise)
			.def("GetRotationTo",&Ogre::Vector3::getRotationTo)
			.def(luabind::self*luabind::other<Ogre::Vector3>())
			.def(luabind::self+luabind::other<Ogre::Vector3>())
			.def(luabind::self-luabind::other<Ogre::Vector3>())
			.def(luabind::self/luabind::other<Ogre::Vector3>())
			.def(luabind::self==luabind::other<Ogre::Vector3>())
			.def(luabind::self*Ogre::Real())
			.def(luabind::self+Ogre::Real())
			.def(luabind::self-Ogre::Real())
			.def(luabind::self/Ogre::Real())
			.def(luabind::tostring(luabind::self))
	];
	luabind::module(m_L)[
		luabind::class_<Ogre::Vector2>("Vector2")
			.def(luabind::constructor<Ogre::Real,Ogre::Real>())
			.def(luabind::constructor<>())
			.def(luabind::constructor<Ogre::Vector2>())
			.def_readwrite("x",&Ogre::Vector2::x)
			.def_readwrite("y",&Ogre::Vector2::y)
			.def("Distance",&Ogre::Vector2::distance)
			.def("SquaredDistance",&Ogre::Vector2::squaredDistance)
			.def("CrossProduct",&Ogre::Vector2::crossProduct)
			.def("Length",&Ogre::Vector2::length)
			.def("SquaredLength",&Ogre::Vector2::squaredLength)
			.def("DotProduct",&Ogre::Vector2::dotProduct)
			.def(luabind::tostring(luabind::self))
	];
	luabind::module(m_L)[
		luabind::class_<Ogre::Vector4>("Vector4")
			.def(luabind::constructor<Ogre::Real,Ogre::Real,Ogre::Real,Ogre::Real>())
			.def(luabind::constructor<>())
			.def(luabind::constructor<Ogre::Vector4>())
			.def_readwrite("x",&Ogre::Vector4::x)
			.def_readwrite("y",&Ogre::Vector4::y)
			.def_readwrite("z",&Ogre::Vector4::z)
			.def_readwrite("w",&Ogre::Vector4::w)
			.def("DotProduct",&Ogre::Vector4::dotProduct)
			.def(luabind::tostring(luabind::self))
	];
	luabind::module(m_L)[
		luabind::class_<Ogre::Quaternion>("Quaternion")
			.def(luabind::constructor<Ogre::Real,Ogre::Real,Ogre::Real,Ogre::Real>())
			.def(luabind::constructor<>())
			.def(luabind::constructor<Ogre::Quaternion&>())
			.def_readwrite("x",&Ogre::Quaternion::x)
			.def_readwrite("y",&Ogre::Quaternion::y)
			.def_readwrite("z",&Ogre::Quaternion::z)
			.def_readwrite("w",&Ogre::Quaternion::w)
			.def("Dot",&Ogre::Quaternion::Dot)
			.def("XAxis",&Ogre::Quaternion::xAxis)
			.def("YAxis",&Ogre::Quaternion::yAxis)
			.def("ZAxis",&Ogre::Quaternion::zAxis)
			.def("GetPitch",&Ogre::Quaternion::getPitch)
			.def("GetRoll",&Ogre::Quaternion::getRoll)
			.def("GetYaw",&Ogre::Quaternion::getYaw)
			.def("Normalise",&Ogre::Quaternion::normalise)
			.def("Norm",&Ogre::Quaternion::Norm)
			.def("NLerp",&Ogre::Quaternion::nlerp)
			.def(luabind::self*luabind::other<Ogre::Vector3>())
			.def(luabind::self+luabind::other<Ogre::Quaternion>())
			.def(luabind::self-luabind::other<Ogre::Quaternion>())
			.def(luabind::tostring(luabind::self))
	];


	Load("sys/vector.lua");
	Load("sys/objectmanager.lua");
	Load("sys/core.lua");

	for (unsigned int i = 0; i < m_paths.size(); i++){
		if(!this->LoadScripts(m_paths[i])){
			return false;
		}
	}
	luabind::set_pcall_callback(&luabind_pcall);

	return true;
}

void LuaEngine::Shut(){
	if (m_L != nullptr){
		lua_close(m_L);
		m_L = nullptr;
	}
}

void LuaEngine::Load(const char* filename){
	luaL_dofile(m_L,filename);
}

void LuaEngine::Call(const char* functionName){

}

int LuaEngine::AtPanic(lua_State* s){
	const char* error = lua_tostring(s,-1);
	lua_pop(s,1);
	printf("LUA_ERROR: %s\n",error);
	__debugbreak();
	return 0;
}

#ifdef _WIN32
#include <io.h>
#endif
// Will load all *.lua files in a specific directory
bool LuaEngine::LoadScripts(const Ogre::String& path){
#ifdef _WIN32
	WIN32_FIND_DATA ffd;
	LARGE_INTEGER filesize;
	HANDLE hFind = INVALID_HANDLE_VALUE;
	DWORD dwError=0;
	Ogre::String dir = path;
	Ogre::String search_dir = path+"*.lua";
	hFind = FindFirstFile(search_dir.c_str(),&ffd);
	if (INVALID_HANDLE_VALUE == hFind){
		System::Notify("Could not read directory "+dir,"File read error");
		return false;
	}
	do {
		if (ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY){
			System::Msg(ffd.cFileName);
		}
		else {
			filesize.LowPart = ffd.nFileSizeLow;
			filesize.HighPart = ffd.nFileSizeHigh;
			_tprintf(TEXT("Found  %s   %ld bytes\n"), ffd.cFileName, filesize.QuadPart);
			Ogre::String file = dir + ffd.cFileName;
			luaL_loadfile(m_L,file.c_str());
			lua_pcall(m_L,0,0,0);
			#ifdef DEV_MODE
			struct stat attrib;
			stat(file.c_str(),&attrib);
			m_files.push_back(LuaFileInfo(file,attrib.st_mtime));
			#endif
		}
	} while (FindNextFile(hFind,&ffd)!=0);
	dwError=GetLastError();
	if (dwError!=ERROR_NO_MORE_FILES){
		return false;
	}
	FindClose(hFind);
#endif
	return true;
}

void LuaEngine::CheckFiles(GameTime* gameTime){
#ifdef WIN32
	m_timer += gameTime->DeltaTime();
	if (m_timer>=m_timeLimit){
		if (!m_files.empty()){
			for (unsigned int i = 0; i < m_files.size(); i++){	
				struct stat attrib;
				stat(m_files[i].m_filename.c_str(),&attrib);
				time_t changeDate = attrib.st_mtime;
				if (m_files[i].m_time!=changeDate){
					luaL_loadfile(m_L,m_files[i].m_filename.c_str());
					lua_pcall(m_L,0,0,0);
					std::cout << m_files[i].m_filename << " has been modified\n";
					m_files[i].m_time = changeDate;
				}
			}
		}
		m_timer = 0.0f;
	}
#endif
}

int luabind_pcall(lua_State* L){
	lua_Debug d;
	lua_getstack(L,1,&d);
	lua_getinfo(L,"Sln",&d);
	std::string err = lua_tostring(L,-1);
	std::stringstream msg;
	msg << d.namewhat << ":" << d.currentline;
	if (d.name!=0){
		msg << "(" << d.namewhat << " " << d.name << ")";
	}
	msg << " " << err;
	lua_pushstring(L,msg.str().c_str());
	System::Log(msg.str());
	return 1;
}

}